
package general.semantics;

import art.applications.seek.Result;
import art.applications.seek.Seeker;
import art.applications.seek.Status;
import art.applications.seek.implementations.SimpleSeeker;

import general.art.Link;
import general.art.Node;
import general.art.NodeTypes;

import java.sql.SQLException;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.SortedSet;


/**
 * 
 * This class does all of the interaction with ART. It basically provides three main functionalities: 
 * populating art with nodes, seeking() -sorting the relevance of the results- and spiting back the results from Art.
 * 
 * @author Hood
 *
 */
public class ArtAccessor{

    

    /** Name of the database. */ 
    protected static String sDBname = "test";
    
    /** Name of the node table. */ 
    protected static String sDBTable1 = "NodesT";
    
    /** Name of the link table. */ 
    protected static String sDBTable2 = "LinksT";
    
    /** Loading Art message. */ 
    protected static String sLoadingART = "Loading Art ......";
    
    /**
     * Max no of iterations.
     */
    protected static final int NO_OF_ITTERATIONS = 5;

    /** Number of levels deep that the recursion would need to go and get links. */
    protected static final int DEPTH = 5;
    
    /** Current Depth in recursion. */ 
    protected static final int INITIALDEPTH = 0;
    
    /**
     * This is the weight representing the Negative seeding nodes in Art.
     */
    protected static final double NEGATIVE_WEIGHT = -1.0;
    
    /**
     * This is the weight representing the Positive seeding nodes in Art.
     */
    protected static final double POSITIVE_WEIGHT = 1.0;
    
    
    /** Status of the query seed. */ 
    protected String mQuerySeed;
    

    
    /** String builder to hold the string written by ART's seeker. */
    private StringBuilder mSb = new StringBuilder();

    /** Simple seeker that implements the Seeker class in ART. The simple seeker
     * provides all of the functionalities needed by the server.
     * */
   private SimpleSeeker<NodeTypes> mSeeker  =  new SimpleSeeker<NodeTypes>(mSb, Seeker.Verbosity.SIMPLE, NO_OF_ITTERATIONS);

    /** FileAccessor class to be replaced be DBAccessor. */ 
   // private DBAccessorInterface mDB = new DBAccessor(sDBname, sDBTable1, sDBTable2);

    /** A linked-list of Links objects that would hold links to a seeding node. */
private LinkedList<Link> mLinks;

    /** This holds a sorted set of results from ART. */
    private SortedSet<Result<NodeTypes>> mRes;

    /** The iterator that holds the results from ART. */
    private Iterator<Result<NodeTypes>> mResItr;

    /** A Hash-table that ensures that a seeding node is not loaded twice.  */
    private Hashtable<Integer, Boolean> mPopHash;


    /**
     * This is the ArtAccessor constructor. 
     * It creates a simple Art seeker and a hash-table holding the loaded nodes into art. 
     */
    public ArtAccessor() {
        
        /* create the seeker we are going to use */
        //mSeeker    =  new SimpleSeeker<NodeTypes>(mSb, Seeker.Verbosity.SIMPLE, NO_OF_ITTERATIONS);
        
        /* hash table only created once for each node */
        mPopHash   = new Hashtable<Integer, Boolean>(); 
    }
    
    
    /**
     * This method gets called by the client side to populate art with nodes for every new query. The method uses 
     * the getRelations() method to populate art with the nodes for every query seeding node passed. The weight of 
     * the seeding nodes are currently set to be either 1.0 (Good) or -1.0 (Bad). 
     * 
     * @param querySeed   seed node to find all the links to.
     * @param weight      weight of this seed node.
     * 
     */
    public void populateArt(final Node querySeed, final double weight) {

        
        mQuerySeed = querySeed + " ";

        System.out.println(sLoadingART);
        
        
        if (weight == NEGATIVE_WEIGHT){
            
            /* sets the status of the node */
           // mSeeker.setStatus(querySeed, Status.NEGATIVE);
            mQuerySeed += Status.NEGATIVE;
            
            System.out.println(mQuerySeed);
            
        }else if (weight == POSITIVE_WEIGHT){
            
            /* sets the status of the node */
           // mSeeker.setStatus(querySeed, Status.POSITIVE);
            mQuerySeed += Status.POSITIVE;
            
            System.out.println(mQuerySeed);

            /* recursively add connected nodes */
            getRelations(querySeed, INITIALDEPTH);
        }else{
            
            /* sets the status of the node */
           // mSeeker.setStatus(querySeed, Status.UNKNOWN);
            mQuerySeed += Status.UNKNOWN;
            System.out.println(mQuerySeed);
            
            /* recursively add connected nodes */
            getRelations(querySeed, INITIALDEPTH);
        }
        
        
    }

    
    /**
     * Finishes the population stage, and instructs art to now seek. 
     * Seeking means sort the results according to their relevance.
     * 
     * @return String   This the Art seeker to string output.
     * 
     */
    public String seekOnArt() {
        mRes = mSeeker.seek();
        mResItr = mRes.iterator();
        
        return mSeeker.toString();
    }
    
    /**
     * This method recursively populates are with the relevant nodes from the database. 
     * The method starts with a particular seeding node and branches some many levels deep (DEPTH) 
     * adding all of the links for the nodes hit. The whole art population ensures that there is no 
     * node added twice in Art which can help improving the efficiency.
     *  
     * @param seedNode  Seed node to get the links of.
     * @param depth     Current depth, Depth starts with "mDepth" value and decrements till 0. 
     * 
     */
    private void getRelations(final Node seedNode, final int depth){

        
        if (mPopHash.containsKey(seedNode.getKey())) {
            return;
        }
        
        mPopHash.put(seedNode.getKey(), true);
        

        
        if (depth == DEPTH){ return;}

       

        for (Link l : mLinks){

            mSeeker.addLink(l.getNode1(), l.getNode2());

            
            /** 
             * recursively call the getRelations() method to get the links of each of the links in 
             * the links LinkedList.
             */


            if (seedNode.getKey() == l.getNode1().getKey()) {
                getRelations(l.getNode2(), depth+1);
            } else {
                getRelations(l.getNode1(), depth+1);
            }
        }

    }



    /**
     * This method returns the next result node in Art's results set iterator.
     * The class would return a node every-time even if the node is null.
     * 
     * @return Result   Get the first result from ART seeker
     */
    public Node getNextRes() {
        
        Node nextNode = null;

        if (mResItr.hasNext()){

            final Result<NodeTypes> nextRes = (Result<NodeTypes>) mResItr.next();
            nextNode = (Node) nextRes.node();
        }


        return  nextNode;

    }

}